package com.yc.cloud.admin.service.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yc.cloud.admin.dto.request.AlarmRecordCreateReqDTO;
import com.yc.cloud.admin.dto.request.AlarmRecordHandleReqDTO;
import com.yc.cloud.admin.dto.request.AlarmRecordUpdateReqDTO;

import com.yc.cloud.admin.service.AlarmRecordService;
import com.yc.cloud.admin.service.DetectionPositionService;
import com.yc.cloud.admin.service.HwDeviceService;

import com.yc.cloud.admin.vo.AlarmRecordVo;
import com.yc.cloud.admin.vo.DetectionPositionVo;
import com.yc.cloud.common.basic.dto.BasePageReqDTO;
import com.yc.cloud.admin.dto.request.AlarmRecordListParam;
import com.yc.cloud.common.basic.exception.Asserts;
import com.yc.cloud.common.orm.CommonPage;

import com.yc.cloud.common.oss.service.OssFileService;
import com.yc.cloud.entity.AlarmRecord;
import com.yc.cloud.entity.AlgAlgorithm;
import com.yc.cloud.entity.AlgStrategyRule;
import com.yc.cloud.entity.HwDevice;
import com.yc.cloud.mapper.AlarmRecordMapper;
import com.yc.cloud.mapper.AlgAlgorithmMapper;
import com.yc.cloud.mapper.AlgStrategyRuleMapper;
import com.yc.cloud.security.utils.AdminUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 告警事件记录表 服务实现类
 * </p>
 *
 * @author kinggu
 * @since 2025-07-16
 */
@Slf4j
@Service
public class AlarmRecordServiceImpl extends ServiceImpl<AlarmRecordMapper, AlarmRecord> implements AlarmRecordService {

    @Resource
    private AlgAlgorithmMapper algAlgorithmMapper;

    private final DetectionPositionService detectionPositionService;

    private final OssFileService ossFileService;

    @Resource
    private AlgStrategyRuleMapper algStrategyRuleMapper;

    private final HwDeviceService hwDeviceService;

    public AlarmRecordServiceImpl(HwDeviceService hwDeviceService, DetectionPositionService detectionPositionService,
            OssFileService ossFileService) {
        this.hwDeviceService = hwDeviceService;
        this.detectionPositionService = detectionPositionService;
        this.ossFileService = ossFileService;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean create(AlarmRecordCreateReqDTO createReqDTO) {
        AlarmRecord entity = new AlarmRecord();
        BeanUtils.copyProperties(createReqDTO, entity);
        return save(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean update(AlarmRecordUpdateReqDTO updateReqDTO) {
        // 获取原始记录
        AlarmRecord originalRecord = getById(updateReqDTO.getId());
        if (originalRecord == null) {
            return false;
        }

        AlarmRecord entity = new AlarmRecord();
        BeanUtils.copyProperties(updateReqDTO, entity);

        // 如果状态发生变化且变为已处理状态（已关闭或误报），且设置了处理时间，则计算处理时长
        boolean isProcessed = entity.getStatus() != null &&
                (entity.getStatus() == 2 || entity.getStatus() == 3); // 2-已关闭, 3-误报
        boolean statusChanged = originalRecord.getStatus() == null ||
                !originalRecord.getStatus().equals(entity.getStatus());

        if (isProcessed && statusChanged && entity.getHandleTime() != null && originalRecord.getAlarmTime() != null) {
            // 计算从告警时间到处理时间的秒数
            long durationSeconds = java.time.Duration.between(
                    originalRecord.getAlarmTime(),
                    entity.getHandleTime()).getSeconds();

            // 设置处理时长
            entity.setHandleDuration((int) durationSeconds);
            log.info("告警处理时长计算: 告警ID={}, 处理时长={}秒", entity.getId(), durationSeconds);
        }

        return updateById(entity);
    }

    @Override
    public CommonPage<AlarmRecordVo> list(BasePageReqDTO pageReqDTO, AlarmRecordListParam param) {
        QueryWrapper<AlarmRecord> queryWrapper = new QueryWrapper<>();

        // 精确筛选：算法ID
        if (param != null && param.getAlgorithmId() != null) {
            queryWrapper.eq(AlarmRecord.AlgorithmId, param.getAlgorithmId());
        }
        // 精确筛选：处理状态
        if (param != null && param.getStatus() != null) {
            queryWrapper.eq(AlarmRecord.Status, param.getStatus());
        }
        // 精确筛选：摄像头ID（设备ID）
        if (param != null && param.getCameraId() != null) {
            queryWrapper.eq(AlarmRecord.DeviceId, param.getCameraId());
        }
        // 时间范围筛选：告警开始时间
        if (param != null && param.getStartTime() != null) {
            queryWrapper.ge(AlarmRecord.AlarmTime, param.getStartTime());
        }
        // 时间范围筛选：告警结束时间
        if (param != null && param.getEndTime() != null) {
            queryWrapper.le(AlarmRecord.AlarmTime, param.getEndTime());
        }
        // 关键字模糊：通过 BasePageReqDTO.keyword 统一处理
        if (StrUtil.isNotBlank(pageReqDTO.getKeyword())) {
            String keyword = pageReqDTO.getKeyword();
            // 先按设备SN或设备名称模糊，找到设备ID集合
            List<Long> matchedDeviceIds = hwDeviceService.lambdaQuery()
                    .like(HwDevice::getDeviceSn, keyword)
                    .or()
                    .like(HwDevice::getName, keyword)
                    .list()
                    .stream().map(HwDevice::getId).collect(Collectors.toList());

            // 组合 (device_location LIKE ? OR device_id IN (?))
            if (matchedDeviceIds != null && !matchedDeviceIds.isEmpty()) {
                queryWrapper.and(w -> w.like(AlarmRecord.DeviceLocation, keyword)
                        .or().in(AlarmRecord.DeviceId, matchedDeviceIds));
            } else {
                queryWrapper.like(AlarmRecord.DeviceLocation, keyword);
            }
        }

        // 排序
        if (StrUtil.isNotEmpty(pageReqDTO.getSortBy())) {
            // 注意：pageReqDTO.getSortBy() 需要是数据库中的列名（驼峰转下划线），请注意防护SQL注入
            if (Objects.equals(BasePageReqDTO.ORDER_DESC, pageReqDTO.getOrder())) {
                queryWrapper.orderByDesc(StrUtil.toUnderlineCase(pageReqDTO.getSortBy()));
            } else {
                queryWrapper.orderByAsc(StrUtil.toUnderlineCase(pageReqDTO.getSortBy()));
            }
        }

        // 根据 page 参数决定是否分页
        if (Boolean.TRUE.equals(pageReqDTO.getPage())) {
            Page<AlarmRecord> page = new Page<>(pageReqDTO.getPageNum(), pageReqDTO.getPageSize());
            Page<AlarmRecord> dbPage = baseMapper.selectPage(page, queryWrapper);
            IPage<AlarmRecordVo> voPage = dbPage.convert(this::convertToVo);
            return CommonPage.restPage(voPage);
        } else {
            List<AlarmRecord> allRecords = baseMapper.selectList(queryWrapper);
            CommonPage<AlarmRecordVo> result = new CommonPage<>();
            result.setList(convertToVoList(allRecords));
            result.setTotal((long) allRecords.size());
            result.setPageNum(1);
            result.setPageSize(allRecords.size());
            result.setTotalPage(1);
            return result;
        }
    }

    private CommonPage<AlarmRecordVo> emptyPage(BasePageReqDTO pageReqDTO) {
        CommonPage<AlarmRecordVo> result = new CommonPage<>();
        result.setList(java.util.Collections.emptyList());
        result.setTotal(0L);
        result.setPageNum(pageReqDTO.getPageNum());
        result.setPageSize(pageReqDTO.getPageSize());
        result.setTotalPage(0);
        return result;
    }

    @Override
    public AlarmRecordVo getVOById(Long id) {
        AlarmRecord entity = getById(id);
        AlarmRecordVo vo = convertToVo(entity);
        if (vo != null) {
            // 获取目标检测位置信息
            List<DetectionPositionVo> detectionPositions = detectionPositionService.listByAlarmRecordId(id);
            vo.setDetectionPositions(detectionPositions);
        }
        return vo;
    }

    @Override
    public List<AlarmRecordVo> convertToVoList(List<AlarmRecord> entityList) {
        if (entityList == null) {
            return null;
        }
        return entityList.stream()
                .map(this::convertToVo)
                .collect(Collectors.toList());
    }

    private AlarmRecordVo convertToVo(AlarmRecord entity) {
        if (entity == null) {
            return null;
        }
        AlarmRecordVo vo = new AlarmRecordVo();
        BeanUtils.copyProperties(entity, vo);

        // 设备基本信息补充：SN、设备名称
        if (entity.getDeviceId() != null) {
            HwDevice d = hwDeviceService.getById(entity.getDeviceId());
            if (d != null) {
                vo.setDeviceSn(d.getDeviceSn());
                vo.setDeviceName(d.getName());
            }
        }

        // 设置图片和视频URL
        if (StrUtil.isNotBlank(entity.getAlarmImageFileId())) {
            vo.setAlarmImageUrl(ossFileService.getOssFileUrl(entity.getAlarmImageFileId()));
        }

        if (StrUtil.isNotBlank(entity.getAlarmMarkedImageFileId())) {
            vo.setAlarmMarkedImageUrl(ossFileService.getOssFileUrl(entity.getAlarmMarkedImageFileId()));
        }

        if (StrUtil.isNotBlank(entity.getAlarmVideoFileId())) {
            vo.setAlarmVideoUrl(ossFileService.getOssFileUrl(entity.getAlarmVideoFileId()));
        }

        return vo;
    }

    @Override
    public AlarmRecord get(Long id) {
        return getById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(Long id) {
        return removeById(id);
    }



    /**
     * 根据设备SN和算法信息，确定最终的告警级别
     * 规则: 策略规则中定义的级别 > 算法定义的默认级别 > 默认值(1-一般)
     */
    private Byte determineAlarmLevel(String deviceSn, AlgAlgorithm algorithm) {
        // 1. 获取设备及其关联的策略ID
        HwDevice device = hwDeviceService.getByDeviceSn(deviceSn);
        if (device == null) {
            // 如果设备或策略不存在，则使用算法的默认级别
            return algorithm.getLevel() != null ? algorithm.getLevel() : 1;
        }

        // 2. 查找对应的策略规则
        QueryWrapper<AlgStrategyRule> ruleQuery = new QueryWrapper<>();
        // 还得加个条件
        ruleQuery.eq(AlgStrategyRule.AlgAlgorithmId, algorithm.getId());

        AlgStrategyRule rule = algStrategyRuleMapper.selectOne(ruleQuery);

        // 3. 决定最终级别
        if (rule != null && rule.getLevel() != null) {
            // 如果策略规则中定义了级别，则优先使用
            return rule.getLevel();
        } else {
            // 否则，使用算法中定义的默认级别
            return algorithm.getLevel() != null ? algorithm.getLevel() : 1; // 1作为最终的默认值
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean handle(Long id, AlarmRecordHandleReqDTO handleReqDTO) {
        // 1. 校验告警记录是否存在
        AlarmRecord alarmRecord = getById(id);
        if (alarmRecord == null) {
            Asserts.fail("告警记录不存在");
        }
        // 2. 准备更新数据
        AlarmRecord updateEntity = new AlarmRecord();
        updateEntity.setId(id);
        updateEntity.setStatus(handleReqDTO.getStatus());
        updateEntity.setHandleResult(handleReqDTO.getHandleResult());
        updateEntity.setHandleTime(LocalDateTime.now());

        // 假设当前操作员ID为1L，实际项目中应从SecurityContext获取
        updateEntity.setHandlerId(AdminUtils.getCurrentUseId());

        // 3. 计算并设置处理时长
        if (alarmRecord.getAlarmTime() != null) {
            long durationSeconds = java.time.Duration.between(
                    alarmRecord.getAlarmTime(),
                    updateEntity.getHandleTime()).getSeconds();
            updateEntity.setHandleDuration((int) durationSeconds);
        }

        return updateById(updateEntity);
    }
}
